﻿using System;
using System.Diagnostics;

namespace Teal.Compiler {

    /// <summary>
    /// 表示一个表达式。
    /// </summary>
    public abstract partial class Expression {

        /// <summary>
        /// 表示一个空表达式。主要用于错误表达式的占位符。
        /// </summary>
        private partial class EmptyExpression {

            /// <summary>
            /// 将当前表达式解析为成员引用。
            /// </summary>
            /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
            /// <param name="memberUsage">当前成员的使用场景。</param>
            /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
            public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
                throw new Unreachable();
            }

        }

        /// <summary>
        /// 将当前表达式解析为成员引用。
        /// </summary>
        /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
        /// <param name="memberUsage">当前成员的使用场景。</param>
        /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
        public virtual MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
            Compiler.error(ErrorCode.none, "应输入类型", this);
            return null;
        }

        /// <summary>
        /// 在解析为注解前先更新当前表达式的值为对应的注解类型。
        /// </summary>
        public virtual void changeToAnnotationName() {
            // 普通成员无需操作。
        }

        /// <summary>
        /// 将当前表达式解析为类型引用。
        /// </summary>
        /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
        /// <param name="memberUsage">当前类型的使用场景。</param>
        /// <returns>返回一个类型引用表达式。如果解析失败则返回 null 。</returns>
        public TypeReference resolveAsType(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
            var resolvedMember = resolveAsMember(currentMemberDefinition, memberUsage);
            var resolvedType = resolvedMember as TypeReference;
            if (resolvedType == null && resolvedMember != null) {
                Compiler.error(ErrorCode.none, String.Format("“{0}”是{1},但被作为类型使用", resolvedMember.signature, resolvedMember.memberType.getReadableName()), this);
            }
            return resolvedType;
        }

    }

    /// <summary>
    /// 表示成员的使用场景。
    /// </summary>
    public enum MemberUsage {

        /// <summary>
        /// 作为导入的目标成员使用。
        /// </summary>
        importTarget,

        /// <summary>
        /// 作为导入的别名成员使用。
        /// </summary>
        importAlias = importTarget,

        /// <summary>
        /// 作为基类型使用。
        /// </summary>
        baseType,

        /// <summary>
        /// 作为约束类型使用。效果将和 baseType 相同。
        /// </summary>
        constraintType = baseType,

        /// <summary>
        /// 作为注解类型使用。
        /// </summary>
        annotation = baseType,

        /// <summary>
        /// 作为返回类型使用。
        /// </summary>
        returnType,

        /// <summary>
        /// 作为变量类型使用。
        /// </summary>
        variableType,

        /// <summary>
        /// 作为显式类型使用。
        /// </summary>
        explicitType,

        /// <summary>
        /// 作为 typeof 的参数使用。
        /// </summary>
        @typeof,

    }

    /// <summary>
    /// 表示一个成员（如方法、字段、类、模块等）定义。
    /// </summary>
    public abstract partial class MemberDefinition {

        /// <summary>
        /// 表示一个泛型参数。
        /// </summary>
        public partial class GenericParameter {

            /// <summary>
            /// 表示结构约束表达式。
            /// </summary>
            public sealed partial class StructConstraintExpression : ConstraintExpression {

                /// <summary>
                /// 将当前表达式解析为成员引用。
                /// </summary>
                /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
                /// <param name="memberUsage">当前成员的使用场景。</param>
                /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
                public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
                    Debug.Assert(memberUsage == MemberUsage.constraintType, "只能解析为约束");
                    return PredefinedTypes.structConstraint;
                }

            }

            /// <summary>
            /// 表示类约束表达式。
            /// </summary>
            public sealed partial class ClassConstraintExpression : ConstraintExpression {

                /// <summary>
                /// 将当前表达式解析为成员引用。
                /// </summary>
                /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
                /// <param name="memberUsage">当前成员的使用场景。</param>
                /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
                public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
                    Debug.Assert(memberUsage == MemberUsage.constraintType, "只能解析为约束");
                    return PredefinedTypes.classConstraint;
                }

            }

            /// <summary>
            /// 表示枚举约束表达式。
            /// </summary>
            public sealed partial class EnumConstraintExpression : ConstraintExpression {

                /// <summary>
                /// 将当前表达式解析为成员引用。
                /// </summary>
                /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
                /// <param name="memberUsage">当前成员的使用场景。</param>
                /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
                public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
                    Debug.Assert(memberUsage == MemberUsage.constraintType, "只能解析为约束");
                    return PredefinedTypes.enumConstraint;
                }

            }

            /// <summary>
            /// 表示默认构造函数约束表达式。
            /// </summary>
            public partial class NewableConstraintExpression {

                /// <summary>
                /// 将当前表达式解析为成员引用。
                /// </summary>
                /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
                /// <param name="memberUsage">当前成员的使用场景。</param>
                /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
                public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
                    Debug.Assert(memberUsage == MemberUsage.constraintType, "只能解析为约束");
                    return PredefinedTypes.defaultConstructorConstraint;
                }

            }

        }

    }

    /// <summary>
    /// 表示一个标识符。
    /// </summary>
    public partial class Identifier {

        /// <summary>
        /// 将当前表达式解析为成员引用。
        /// </summary>
        /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
        /// <param name="memberUsage">当前成员的使用场景。</param>
        /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
        public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {

            // 查找基类时仅查找当前成员的泛型参数，不查询当前成员子成员。
            if (memberUsage == MemberUsage.baseType) {
                var type = currentMemberDefinition.reference.getGenericParameter(value);
                if (type != null) {
                    return type;
                }
                currentMemberDefinition = currentMemberDefinition.container;
            }

            var result = new MemberBindResult();
            currentMemberDefinition.bindMember(value, 0, ref result);
            if (result.type != MemberBindResultType.success) {
                ResolveHelper.reportBindMemberError(result, null, value, memberUsage, this);
                return null;
            }
            return result.found;

        }

        /// <summary>
        /// 在解析为注解前先更新当前表达式的值为对应的注解类型。
        /// </summary>
        public override void changeToAnnotationName() {
            value = String.Concat(char.ToUpper(value[0]), value.Substring(1), "Annotation");
        }

    }

    ///// <summary>
    ///// 表示一个魔法变量。
    ///// </summary>
    //public partial class MagicVariable {

    //    /// <summary>
    //    /// 将当前表达式解析为成员引用。
    //    /// </summary>
    //    /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
    //    /// <param name="memberUsage">当前成员的使用场景。</param>
    //    /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
    //    public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
    //        switch (value) {
    //            case "global":
    //                return currentMemberDefinition.memberReference.parentPackage;
    //            case "callee":
    //                return currentMemberDefinition.memberReference;
    //            case "self":
    //                return currentMemberDefinition.memberReference.parentType;
    //            default:
    //                Compiler.error(ErrorCode.none, "无效的魔法变量（应输入类型）", this);
    //                return null;
    //        }
    //    }

    //}

    /// <summary>
    /// 表示内置类型字面量。
    /// </summary>
    public partial class PredefinedTypeLiteral {

        /// <summary>
        /// 将当前表达式解析为成员引用。
        /// </summary>
        /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
        /// <param name="memberUsage">当前成员的使用场景。</param>
        /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
        public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
            switch (type) {
                case TokenType.@var:
                    return PredefinedTypes.@var;
                case TokenType.@void:
                    return PredefinedTypes.@void;
                case TokenType.@int:
                    return PredefinedTypes.System_Int32;
                case TokenType.@bool:
                    return PredefinedTypes.System_Bool;
                case TokenType.@object:
                    return PredefinedTypes.System_Object;
                case TokenType.@string:
                    return PredefinedTypes.System_String;
                case TokenType.@short:
                    return PredefinedTypes.System_Int16;
                case TokenType.@char:
                    return PredefinedTypes.System_Char;
                case TokenType.@byte:
                    return PredefinedTypes.System_Byte;
                case TokenType.@long:
                    return PredefinedTypes.System_Int64;
                case TokenType.@uint:
                    return PredefinedTypes.System_UInt32;
                case TokenType.@ushort:
                    return PredefinedTypes.System_UIint16;
                case TokenType.@ulong:
                    return PredefinedTypes.System_UInt64;
                case TokenType.@float:
                    return PredefinedTypes.System_Float32;
                case TokenType.@double:
                    return PredefinedTypes.System_Float64;
                default:
                    throw new Unreachable();
            }
        }

    }

    /// <summary>
    /// 表示一个泛型表达式。
    /// </summary>
    public partial class GenericTypeExpression {

        /// <summary>
        /// 将当前表达式解析为成员引用。
        /// </summary>
        /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
        /// <param name="memberUsage">当前成员的使用场景。</param>
        /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
        public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {

            var result = new MemberBindResult();

            // 查找基类时仅查找当前成员的泛型参数，不查询当前成员子成员。
            (memberUsage == MemberUsage.baseType ? currentMemberDefinition.container : currentMemberDefinition).bindMember(elementType.value, genericArguments.Count, ref result);
            if (result.type != MemberBindResultType.success) {
                ResolveHelper.reportBindMemberError(result, null, elementType.value, memberUsage, this);
                return null;
            }

            return ResolveHelper.makeGenericMember(result.found, genericArguments, currentMemberDefinition, memberUsage, this);
        }

    }

    /// <summary>
    /// 表示一个数组类型表达式。
    /// </summary>
    public partial class ArrayTypeExpression {

        /// <summary>
        /// 将当前表达式解析为成员引用。
        /// </summary>
        /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
        /// <param name="memberUsage">当前成员的使用场景。</param>
        /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
        public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
            var resolvedElementType = elementType.resolveAsType(currentMemberDefinition, memberUsage);
            if (resolvedElementType == null) {
                return null;
            }
            ResolveHelper.checkVaribaleType(resolvedElementType, this);
            return PredefinedTypes.System_Array_T.makeGenericType(resolvedElementType);
        }

    }

    /// <summary>
    /// 表示一个指针表达式。
    /// </summary>
    public partial class PtrTypeExpression {

        /// <summary>
        /// 将当前表达式解析为成员引用。
        /// </summary>
        /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
        /// <param name="memberUsage">当前成员的使用场景。</param>
        /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
        public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
            var resolvedElementType = elementType.resolveAsType(currentMemberDefinition, memberUsage);
            if (resolvedElementType == null) {
                return null;
            }
            if (resolvedElementType != PredefinedTypes.@void) {
                ResolveHelper.checkVaribaleType(resolvedElementType, this);
            }
            return PredefinedTypes.System_Ptr_T.makeGenericType(resolvedElementType);
        }

    }

    /// <summary>
    /// 表示一个成员调用表达式。
    /// </summary>
    public partial class MemberCallExpression {

        /// <summary>
        /// 将当前表达式解析为成员引用。
        /// </summary>
        /// <param name="currentMemberDefinition">当前表达式所在的成员定义。</param>
        /// <param name="memberUsage">当前成员的使用场景。</param>
        /// <returns>返回一个成员引用表达式。如果解析失败则返回 null。</returns>
        public override MemberReference resolveAsMember(MemberDefinition currentMemberDefinition, MemberUsage memberUsage) {
            var targetMember = target.resolveAsMember(currentMemberDefinition, memberUsage);

            // ExprValue.prop
            var targetContainer = targetMember as NamespaceReference;
            if (targetContainer == null) {
                if (targetMember != null) {
                    Compiler.error(ErrorCode.none, String.Format("无法获取{0}“{1}”的子成员", targetMember.memberType.getReadableName(), targetMember.signature), target);
                }
                return null;
            }

            if(targetMember.memberType == MemberType.typeParameter) {
                Compiler.error(ErrorCode.none, String.Format("无法通过{0}“{1}”获取子成员", targetMember.memberType.getReadableName(), targetMember.signature), target);
                return null;
            }

            // Expr.prop
            var argumentIdentifier = argument as Identifier;
            if (argumentIdentifier != null) {
                var result = new MemberBindResult();
                currentMemberDefinition.bindMember(targetContainer, argumentIdentifier.value, 0, ref result);
                if (result.type != MemberBindResultType.success) {
                    ResolveHelper.reportBindMemberError(result, targetContainer, argumentIdentifier.value, memberUsage, argument);
                    return null;
                }

                return result.found;
            }

            // Expr.prop<int>
            var argumentGenericExpression = argument as GenericTypeExpression;
            if (argumentGenericExpression != null) {
                var result = new MemberBindResult();
                currentMemberDefinition.bindMember(targetContainer, argumentGenericExpression.elementType.value, argumentGenericExpression.genericArguments.Count, ref result);
                if (result.type != MemberBindResultType.success) {
                    ResolveHelper.reportBindMemberError(result, targetContainer, argumentGenericExpression.elementType.value, memberUsage, argument);
                    return null;
                }

                // 生成泛型。
                return (MemberReference)ResolveHelper.makeGenericMember(result.found, argumentGenericExpression.genericArguments, currentMemberDefinition, memberUsage, argumentGenericExpression);
            }

            // Expr.Expr
            throw new Unreachable();
        }

        /// <summary>
        /// 在解析为注解前先更新当前表达式的值为对应的注解类型。
        /// </summary>
        public override void changeToAnnotationName() {
            argument.changeToAnnotationName();
        }

    }

}
